﻿using DeHeng_Mes.Constant;
using DeHeng_Mes.Utils;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DeHeng_Mes.Dao.PlcDao
{
    public class PlcDao
    {
        /// <summary>
        /// 通用方法：返回指定字段名的 bool 值
        /// </summary>
        /// <param name="types"></param>
        /// <param name="targetTypeName"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public bool GetBoolFieldValue(Dictionary<object, Type> types, string targetTypeName, string fieldName)
        {
            foreach (var item in types)
            {
                string name = item.Key.GetType().Name;
                // 匹配类型名称
                if (name.Contains(targetTypeName))
                {
                    var fields = item.Value.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                    foreach (var field in fields)
                    {
                        // 获取字段名
                        string name1 = field.Name.Contains("k__BackingField")? field.Name.Replace("<", "").Replace(">k__BackingField", ""): field.Name;

                        if (name1.Equals(fieldName) && field.FieldType == typeof(bool))
                        {
                            // 获取并返回字段值
                            return (bool)field.GetValue(item.Key);
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 通用方法：返回指定字段名的 string 值
        /// </summary>
        /// <param name="types"></param>
        /// <param name="targetTypeName"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public string GetStringFieldValue(Dictionary<object, Type> types, string targetTypeName, string fieldName)
        {
            string value = "";
            foreach (var item in types)
            {
                string name = item.Key.GetType().Name;
                // 匹配类型名称
                if (name.Contains(targetTypeName))
                {
                    var fields = item.Value.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                    foreach (var field in fields)
                    {

                        // 获取字段名
                        string name1 = field.Name.Contains("k__BackingField")
                                         ? field.Name.Replace("<", "").Replace(">k__BackingField", "")
                                         : field.Name;

                        if (name1.Equals(fieldName))
                        {
                            // 获取并返回字段值
                            object fieldValue = field.GetValue(item.Key);
                            //判断是否需要做数据转换
                            if (targetTypeName.Equals(SystemConstant.DeviceErrorMessage))
                            {
                                value = ParseS7WString((byte[])fieldValue).ToString();
                            }
                            else if (targetTypeName.Equals(SystemConstant.Code) || targetTypeName.Equals("Check"))
                            {
                                value = ParseS7String((byte[])fieldValue).ToString();
                            }
                            else if (targetTypeName.Equals(SystemConstant.Collection))
                            {
                                value = ConvertPlcDateAndTime((byte[])fieldValue).ToString();
                            }
                            else
                            {
                                value = fieldValue.ToString();
                            }
                        }
                    }
                }
            }
            return value;
        }


        /// <summary>
        /// 通用方法：返回指定类型下所有字段的名称和值
        /// </summary>
        /// <param name="types"></param>
        /// <param name="targetTypeName"></param>
        /// <returns></returns>
        public Dictionary<string, object> GetFieldValues(Dictionary<object, Type> types, string targetTypeName)
        {
            Dictionary<string, object> fieldValues = new Dictionary<string, object>();
            foreach (var item in types)
            {
                string name = item.Key.GetType().Name;
                // 匹配类型名称
                if (name.Contains(targetTypeName))
                {
                    // 获取所有字段（包括私有字段和实例字段）
                    var fields = item.Value.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                    // 遍历字段
                    foreach (var field in fields)
                    {
                        // 获取字段名
                        string fieldName = field.Name.Contains("k__BackingField")
                                         ? field.Name.Replace("<", "").Replace(">k__BackingField", "")
                                         : field.Name;
                        // 获取字段值
                        object fieldValue = field.GetValue(item.Key);
                        //处理String类型数据
                        if (targetTypeName.Equals(SystemConstant.DeviceErrorMessage))
                        {
                            fieldValue = ParseS7WString((byte[])fieldValue);
                        }
                        else if (targetTypeName.Equals(SystemConstant.Code) || targetTypeName.Equals(SystemConstant.CodeHelper))
                        {
                            fieldValue = ParseS7String((byte[])fieldValue);
                        }
                        else if (targetTypeName.Equals(SystemConstant.Collection))
                        {
                            fieldValue = ConvertPlcDateAndTime((byte[])fieldValue);
                        }
                        // 将字段名和值添加到字典
                        fieldValues.Add(fieldName, fieldValue);
                    }
                }
            }
            return fieldValues;
        }

        /// <summary>
        /// 解析WString数据
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="startOffset"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private string ParseS7WString(byte[] bytes, int startOffset = 4, int length = -1)
        {
            // 如果未指定长度，则默认解析到结尾
            length = length > 0 ? length : bytes.Length - startOffset;

            // 提取有效部分并使用大端序解码
            byte[] validBytes = new byte[length];
            Array.Copy(bytes, startOffset, validBytes, 0, length);

            string result = Encoding.BigEndianUnicode.GetString(validBytes);
            return result.TrimEnd('\0'); // 去除末尾空字符
        }

        /// <summary>
        /// 解析String数据
        /// </summary>
        /// <param name="rawData"></param>
        /// <returns></returns>
        public static string ParseS7String(byte[] rawData)
        {
            /*if (rawData == null || rawData.Length < 2) return string.Empty;

            int actualLength = rawData[1]; // 获取当前字符串的实际长度

            string code = string.Empty;

            if(rawData.Length > 200)
            {
                code = Encoding.ASCII.GetString(rawData, 2, actualLength);
            }
            else
            {
                code = Encoding.ASCII.GetString(rawData, 0, actualLength).Trim();
            }

            return code.TrimEnd('\0');*/

            if (rawData == null || rawData.Length < 2)
                return string.Empty;

            string code = string.Empty;

            int actualLength = rawData[1]; // 获取当前字符串的实际长度
            int maxPossibleLength = rawData.Length - 2; // 最大可能读取的长度

            // 防止 actualLength 超出实际数据范围
            if (actualLength > maxPossibleLength)
                actualLength = maxPossibleLength;

            if (rawData.Length > 200)
            {
                code = Encoding.ASCII.GetString(rawData, 2, actualLength);
            }
            else
            {
                code = Encoding.ASCII.GetString(rawData, 0, actualLength).Trim();
            }

            return code.TrimEnd('\0');
        }

        /// <summary>
        ///  解析DateAndTime类型数据
        /// </summary>
        /// <param name="dateAndTime"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static DateTime ConvertPlcDateAndTime(byte[] dateAndTime)
        {
            if (dateAndTime.Length != 8)
                throw new ArgumentException("DateAndTime 字节数组长度必须为 8");

            int year = BCDToInt(dateAndTime[0]) + 2000;
            int month = BCDToInt(dateAndTime[1]);
            int day = BCDToInt(dateAndTime[2]);
            int hour = BCDToInt(dateAndTime[3]);
            int minute = BCDToInt(dateAndTime[4]);
            int second = BCDToInt(dateAndTime[5]);
            int millisecond = BCDToInt(dateAndTime[6]) * 10;

            return new DateTime(year, month, day, hour, minute, second, millisecond);
        }

        // 辅助方法：将 BCD 格式转换为整数
        private static int BCDToInt(byte bcd)
        {
            return ((bcd >> 4) * 10) + (bcd & 0x0F);
        }

    }
}
